
/**
 * @class Kohive.app.PhotosController
 * @extends ExtMVC.Controller
 * Manages the Album and Image models, renders the Photos main view and emits events when
 * Album and Image changes are made
 */
Kohive.app.PhotosController = Ext.extend(Kohive.controllers.KohiveController, {
	name				: 'photos',

	currentAlbum		: {},

	originalStore		: [],

	constructor			: function() {
		Kohive.app.PhotosController.superclass.constructor.call(this, {
					viewsPackage	: Kohive.views.photos
				});

		this.initEvents();
		this.initListeners();

		// TODO: This is a relic of old MVC, remove it once on ExtMVC 0.6 or above
		this.registerAction('index', this.index);
	},

	/**
	 * @action index 
	 * Renders the index view
	 */
	index				: function() {
		this.indexWindow = this.renderView('index', {
					albumStore	: Kohive.models.Album.findAll({
								url	: this.scopedUrl('albums')
							}),
					closeAction	: 'hide',
					autoShow	: true,
					listeners	: {
						scope				: this,
						'load-album'		: this.loadAlbumImages,
						'refresh'			: this.loadAlbumImages
								.createDelegate(this, [null, null, true]),
						'filter'			: this.filter,
						'show-image'		: this.show,
						'update-image'		: this.update,
						'destroy-image'		: this.destroy,
						'destroy-album'		: this.destroyAlbum,
						'create-album'		: this.createAlbum,
						'create-rss-album'	: this.createRssAlbum
					}
				});

		this.indexWindow.show();

		this.fireEvent('index');
	},

	/**
	 * @action update
	 * Updates the given image with the provided arguments
	 * @param {Kohive.models.Image} image The image to update
	 * @param {Object} fields An object containing keys and values to update
	 */
	update				: function(image, fields) {
		this.fireEvent('before-update');

		for (var key in fields) {
			image.set(key, fields[key]);
		};

		// update the tags array - ideally we wouldn't do this here, should be in the model somehow
		image.data.tags = [];
		if (fields.tag_list) {
			Ext.each(image.get('tag_list').split(' '), function(t) {
						image.data.tags.push({
									name	: t
								});
					}, this);
		};

		// update the description_html if description is set
		if (fields.description) {
			image.data.description_html = fields.description.replace("\n",
					"<br />"
			);
		};

		image.save({
					url		: this.scopedUrl(String.format(
							"albums/{0}/images/{1}", image.get('album_id'),
							image.get('id')
					)),
					scope	: this,
					success	: function() {
						this.fireEvent('update', image);
					}
				});
	},

	/**
	 * @action destroy 
	 * Destroys the passed photo and fires a image-destroyed event
	 * @param {Kohive.models.Image} image The image to destroy
	 */
	destroy				: function(image) {
		image.destroy({
					url		: this.scopedUrl(String.format(
							"albums/{0}/images/{1}.json",
							image.get('album_id'), image.get('id')
					)),
					scope	: this,
					success	: function() {
						this.loadAlbumImages();
						this.fireEvent('image-destroyed', image);
					}
				});
	},

	/**
	 * Filters the currently loaded images with options from a filter bar
	 * @param {Object} filtersApplied The object of currently applied filters.  Something like:
	 * {authors: [1, 2, 5], tags: ['cat', 'dog']}
	 */
	filter				: function(filters) {
		var hive = Kohive.OS.getCurrentHive();

		// for some reason passing the params option to findAll isn't working, so build url manually :/
		var url = this.scopedUrl('albums/'
				+ this.currentAlbum[Kohive.OS.getCurrentHiveId()].get('id')
				+ '/images?'), tags = filters.tags, authors = filters.authors, conditions = [];

		if (tags && tags.length > 0)
			conditions.push(String.format("tags={0}", tags.join(',')));
		if (authors && authors.length > 0)
			conditions.push(String.format("membership_ids={0}", authors
							.join(',')));

		this.loadAlbumImages(this.currentAlbum[Kohive.OS.getCurrentHiveId()],
				url + conditions.join("&")
		);
	},

	/**
	 * @action show 
	 * Fires an event telling subscriber views to update to the given photo
	 * @param {Kohive.models.Image} image The image to show
	 */
	show				: function(image) {
		this.fireEvent('show-image', image);
	},

	/**
	* @action createFromUrl
	* 
	* @param {String} url the Url of the album to create
	*/
	createFromUrl		: function(url) {
		this.fireEvent('before-create-image', url);

		var hive = Kohive.OS.getCurrentHive();

		new Kohive.models.Image({
					author_membership_id	: hive.get('id'),
					file_url				: url
				}).save({
					url		: this.scopedUrl('albums/'
							+ this.currentAlbum[Kohive.OS.getCurrentHiveId()]
									.get('id') + '/images'),
					scope	: this,
					success	: function(album) {
						this.fireEvent('image-created', url);
					},
					failure	: function() {
						this.fireEvent('create-image-failed', url);
					}
				});
	},

	/**
	* @action createFromFlickr
	* @param {String} url the Url of the flickr album to import
	*/
	createFromFlickr	: function(url, form) {
		this.fireEvent('before-create-image', url);

		var hive = Kohive.OS.getCurrentHive();

		var model = new Kohive.models.Album({});
		model.newRecord = true;

		model.save({
					url		: this.scopedUrl('albums'),
					scope	: this,
					params	: {
						"id"			: this.currentAlbum[Kohive.OS
								.getCurrentHiveId()].get('id'),
						"album[title]"	: url
					},
					success	: function(album) {
						this.fireEvent('image-created', url);
						form.reset();
					},
					failure	: function() {
						this.fireEvent('create-image-failed', url);
					}
				});
	},

	/**
	 * @action createAlbum
	 * Creates a new album with the given title argument
	 * @param {String} title The title of the new album to create
	 */
	createAlbum			: function(title) {
		this.fireEvent('before-create-album', title);

		new Kohive.models.Album({
					author_membership_id	: Kohive.OS.getCurrentHive()
							.get('id'),
					title					: title
				}).save({
					url		: this.scopedUrl('albums'),
					scope	: this,
					success	: function(album) {
						this.fireEvent('album-created', album);
					}
				});
	},

	/**
	 * @action createRssAlbum
	 * Creates a new rss album with the given feed_url argument
	 * @param {String} feed_url The feed url to fetch the images from
	 */
	createRssAlbum		: function(feed_url) {
		this.fireEvent('before-create-album', feed_url);

		new Kohive.models.Album({
					author_membership_id	: Kohive.OS.getCurrentHive()
							.get('id'),
					feed_url				: feed_url,
					type					: 'FeedPhotoAlbum'
				}).save({
					url		: this.scopedUrl('albums'),
					scope	: this,
					success	: function(album) {
						this.fireEvent('rss-album-created', album);
					}
				});
	},

	/**
	 * @action destroyAlbum
	 * Attempts to destroy an album, fires an album-destroyed event if successful
	 * @param {Kohive.models.Album} album The album to destroy
	 */
	destroyAlbum		: function(album) {
		this.fireEvent('before-destroy-album', album);

		album.destroy({
					url		: this.scopedUrl(String.format("albums/{0}", album
									.get('id'))),
					scope	: this,
					success	: function() {
						this.fireEvent('album-destroyed', album);
					}
				});
	},

	/**
	 * @action loadAlbumImages
	 * Loads images for a specific album and fires the images-loaded event
	 * @param {Kohive.models.Album} album The album to load images from
	 * @param {String} url An optional url to use (used by the filter action)
	 * @param {Boolean} newImage True if it is a new image
	 */
	loadAlbumImages		: function(album, url, newImage) {
		var hive = Kohive.OS.getCurrentHive();
		if (!album && !this.currentAlbum[Kohive.OS.getCurrentHiveId()])
			return;
		if (!album && this.currentAlbum[Kohive.OS.getCurrentHiveId()])
			album = this.currentAlbum[Kohive.OS.getCurrentHiveId()];
		this.currentAlbum[Kohive.OS.getCurrentHiveId()] = album;

		this.fireEvent('before-load-images', album);

		// TODO when creating a new album, it only has a 'title' field, no id. so this must be fixed
		// by returning the id in the response from the server when creating a new album.
		var url = url || this.scopedUrl('albums/' + album.data.id + '/images');

		album.images.findAll({
					url			: url,
					sortInfo	: {
						field		: 'created_at',
						direction	: 'DESC'
					},
					listeners	: {
						scope	: this,
						load	: function(store) {
							if (store.proxy.conn.url.split('?').length == 1)
								this.originalStore = store.data.items;
							this.currentStore = store;

							this.fireEvent('images-loaded', store, album);

							var image = store.getAt(0);
							this.fireEvent('show-image', image, newImage);
						}
					}
				});
	},

	/**
	 * TODO: A hacky method to prepend the /memberships/:membership_id/ segment to the front of an AJAX
	 * request url.  This really ought to be handled by the model, so factor it out of here when possible
	 * @param {String} url The url to append to the memberships scope
	 * @return {String} The fully scoped url
	 */
	scopedUrl			: function(url) {
		return String.format("/memberships/{0}/{1}", Kohive.OS.getCurrentHive()
						.get('id'), url);
	},

	/**
	 * Sets up all of the events this controller emits
	 */
	initEvents			: function() {
		this.addEvents(
				/**
		 * @event before-load-images
		 * Fires before the request to load (or refresh) images from an album is sent
		 */
				'before-load-images',

				/**
				 * @event images-loaded
				 * Fired whenever images for a specific album have been retrieved
				 * @param {Ext.data.Store} images A store containing images
				 * @param {Kohive.models.Album} album The album that images were loaded for
				 */
				'images-loaded',

				/**
				 * @event show-image
				 * Fired whenever subscriber views should update the photo they are displaying
				 * @param {Kohive.models.Image} image The new image to display
				 */
				'show-image',

				/**
				 * @event image-destroyed
				 * Fired when a photo has been successfully destroyed
				 * @param {Kohive.models.Image} image The image that was destroyed
				 */
				'image-destroyed',

				/**
				 * @event image-created
				 * Fires when a image has been created using a URL
				 */
				'image-created',

				/**
				 * @event before-create-image
				 * Fires before an image is created from a Url
				 */
				'before-create-image',

				/**
				 * @event create-image-failed
				 * Fires when creating an image failed
				 */
				'create-image-failed',

				/**
				 * @event before-update
				 * Fired before an image update request is sent
				 */
				'before-update',

				/**
				 * @event update
				 * Fired when an image has been successful updated
				 * @param {Kohive.models.Image} image The image that was updated
				 */
				'update',

				/**
				 * @event before-create-album
				 * Fires before the request to create an album is sent
				 */
				'before-create-album',

				/**
				 * @event album-created
				 * Fired when a new album has been successfully created
				 * @param {Kohive.models.Album} album The newly created album
				 */
				'album-created',

				/**
				 * @event rss-album-created
				 * Fired when a new rss album has been successfully created
				 * @param {Kohive.models.Album} album The newly created album
				 */
				'rss-album-created',

				/**
				 * @event album-destroyed
				 * Fired when an album has been destroyed
				 * @param {Kohive.models.Album} album The album that was destroyed
				 */
				'album-destroyed'
		);
	},

	/**
	 * Add listeners to the controller
	 */
	initListeners		: function() {
		this.on('image-created', function() {
					this.loadAlbumImages(null, null, true);
				}, this);
	}

}
);

Kohive.OS.registerController('photos', Kohive.app.PhotosController);